{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import tensorflow as tf\n",
    "import scipy.io\n",
    "from tensorflow.python.framework import function\n",
    "\n",
    "import os, re\n",
    "\n",
    "import claude.utils as cu\n",
    "import claude.tx as tx\n",
    "import claude.claudeflow.autoencoder as ae\n",
    "import claude.claudeflow.helper as cfh\n",
    "import claude.claudeflow.training as cft"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "M=16,SNR=10,seed=1337\n"
     ]
    }
   ],
   "source": [
    "# Parameters\n",
    "# Channel Parameters\n",
    "chParam = cu.AttrDict()\n",
    "chParam.M = 16\n",
    "chParam.w = int(np.log2(chParam.M))\n",
    "if chParam.M == 16:\n",
    "    chParam.SNR = 10\n",
    "elif chParam.M == 64:\n",
    "    chParam.SNR = 18\n",
    "else:\n",
    "    chParam.SNR = 22\n",
    "\n",
    "# Auto-Encoder Parameters\n",
    "aeParam = cu.AttrDict()\n",
    "aeParam.seed = 1337\n",
    "aeParam.constellationDim\t= 2\n",
    "aeParam.constellationOrder\t= chParam.M\n",
    "aeParam.nLayers\t\t= 4\n",
    "aeParam.nHidden \t= 256\n",
    "aeParam.activation  = tf.nn.relu\n",
    "aeParam.dropout\t\t= False\n",
    "aeParam.dtype       = tf.float32\n",
    "\n",
    "# Training Parameters\n",
    "trainingParam = cu.AttrDict()\n",
    "trainingParam.sampleSize\t= 16*chParam.M # Increase for better results (especially if M>16)\n",
    "trainingParam.batchSize \t= 1*chParam.M  # Increase for better results (especially if M>16)\n",
    "trainingParam.learningRate\t= 0.001\n",
    "trainingParam.displayStep\t= 25\n",
    "trainingParam.path\t\t\t= 'results_GMI_AWGN'\n",
    "trainingParam.filename\t\t= 'M{:03d}_seed{:04d}_SNR{:02d}'.format(chParam.M,aeParam.seed,chParam.SNR)\n",
    "trainingParam.earlyStopping = 25\n",
    "trainingParam.iterations = 500\n",
    "trainingParam.summaries = True\n",
    "\n",
    "if trainingParam.summaries:\n",
    "    # tensorboard directory\n",
    "    chHyperParam = ['M','SNR']\n",
    "    aeHyperParam = ['seed']\n",
    "    trainingHyperParam = []\n",
    "\n",
    "    trainingParam.summaryString = ','.join(  [ '{}={}'.format(item,chParam[item]) for item in chHyperParam ]\n",
    "                                            +[ '{}={}'.format(item,trainingParam[item]) for item in trainingHyperParam ]\n",
    "                                            +[ '{}={}'.format(item,aeParam[item]) for item in aeHyperParam ] )\n",
    "\n",
    "    print(trainingParam.summaryString,flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# TF constants\n",
    "one = tf.constant(1,aeParam.dtype)\n",
    "two = tf.constant(2,aeParam.dtype)\n",
    "DIM = tf.constant(aeParam.constellationDim,aeParam.dtype)\n",
    "PI = tf.constant(np.pi,aeParam.dtype)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Logging before flag parsing goes to stderr.\n",
      "W0921 22:18:59.782160 139893023668032 deprecation.py:506] From /home/rasmus/.conda/envs/claudeOnline/lib/python3.6/site-packages/tensorflow/python/ops/init_ops.py:1251: calling VarianceScaling.__init__ (from tensorflow.python.ops.init_ops) with dtype is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Call initializer instance with the dtype argument instead of passing it to the constructor\n"
     ]
    }
   ],
   "source": [
    "tf.set_random_seed(aeParam.seed)\n",
    "np.random.seed(aeParam.seed)\n",
    "\n",
    "# Tx Graph\n",
    "allCombinations = cu.generateUniqueBitVectors(chParam.M)\n",
    "xSeed = tf.constant(allCombinations, aeParam.dtype)\n",
    "X = tf.placeholder( aeParam.dtype, shape=(None, chParam.w) )\n",
    "enc, enc_seed = ae.encoder(X, aeParam, bits=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Channel Graph\n",
    "SNR_lin = cfh.dB2lin(tf.constant(chParam.SNR,aeParam.dtype),'dB')\n",
    "sigma2_noise = one / SNR_lin\n",
    "noise = tf.sqrt(sigma2_noise) * tf.rsqrt(two) * tf.random_normal(shape=tf.shape(enc),dtype=aeParam.dtype)\n",
    "channel = enc + noise"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Rx Graph\n",
    "decoder = ae.decoder(channel, aeParam, bits=True)\n",
    "decoder_sigmoid = tf.sigmoid(decoder)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0921 22:19:00.998221 139893023668032 deprecation.py:323] From /home/rasmus/.conda/envs/claudeOnline/lib/python3.6/site-packages/tensorflow/python/ops/array_ops.py:1354: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.where in 2.0, which has the same broadcast rule as np.where\n"
     ]
    }
   ],
   "source": [
    "# Neural Network GMI metric\n",
    "# the output of the neural network with sigmoid activation can serve as an LLR estimation :)\n",
    "# we basically assume that the decoder neural network has learned a probability distribution of the channel\n",
    "# which we use as auxiliary channel within the receiver\n",
    "sigmoid_LLRs = tf.linalg.transpose( tf.log( (one-decoder_sigmoid) / decoder_sigmoid ) )\n",
    "sigmoid_GMI = cfh.GMI( tf.linalg.transpose(X), sigmoid_LLRs )\n",
    "\n",
    "# Gaussian GMI metric\n",
    "# here we just use a Gaussian auxiliary channel assumption\n",
    "constellation = tf.expand_dims( tf.complex( enc_seed[:,0], enc_seed[:,1]), axis=0 )\n",
    "channel_complex = tf.expand_dims( tf.complex( channel[:,0], channel[:,1]), axis=0 )\n",
    "gaussian_LLRs = cfh.gaussianLLR( constellation, tf.linalg.transpose(xSeed), channel_complex, SNR_lin, chParam.M )\n",
    "gaussian_GMI = cfh.GMI( tf.linalg.transpose(X), gaussian_LLRs )\n",
    "\n",
    "# In this script, the channel is a Gaussian channel, so a Gaussian auxiliary channel assumption is optimal\n",
    "# Therefore: Gaussian GMI > Neural Network GMI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "# bit errors and ber\n",
    "input_bits = tf.cast( X , tf.int32 )\n",
    "output_bits = tf.cast( tf.round( tf.nn.sigmoid( decoder ) ), tf.int32 )\n",
    "bit_compare = tf.not_equal( output_bits, input_bits )\n",
    "bit_errors = tf.reduce_sum( tf.cast( bit_compare, tf.int32 ) ) \n",
    "bit_error_rate = tf.reduce_mean( tf.cast( bit_compare, aeParam.dtype ) )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# loss\n",
    "loss = tf.reduce_mean( tf.nn.sigmoid_cross_entropy_with_logits( labels=X, logits=decoder ) )\n",
    "optimizer = tf.train.AdamOptimizer(learning_rate=trainingParam.learningRate)\n",
    "d_sigmoid_loss = optimizer.minimize(loss)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0921 22:19:03.500999 139893023668032 lazy_loader.py:50] \n",
      "The TensorFlow contrib module will not be included in TensorFlow 2.0.\n",
      "For more information, please see:\n",
      "  * https://github.com/tensorflow/community/blob/master/rfcs/20180907-contrib-sunset.md\n",
      "  * https://github.com/tensorflow/addons\n",
      "  * https://github.com/tensorflow/io (for I/O related ops)\n",
      "If you depend on functionality not listed there, please file an issue.\n",
      "\n"
     ]
    }
   ],
   "source": [
    "metricsDict = {'loss_metric':loss,\\\n",
    "               'ber_metric':bit_error_rate,\\\n",
    "               'gaussian_gmi_metric':gaussian_GMI,\\\n",
    "               'sigmoid_gmi_metric':sigmoid_GMI}\n",
    "meanMetricOpsDict, updateOps, resetOps = cft.create_mean_metrics(metricsDict)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "sess = tf.Session()\n",
    "\n",
    "if trainingParam.summaries:\n",
    "    weights_summaries = tf.summary.merge_all() # without weight/bias histograms\n",
    "    # Summaries\n",
    "    s = [tf.summary.scalar('BER', metricsDict['ber_metric']),\n",
    "         tf.summary.scalar('loss', metricsDict['loss_metric']),\n",
    "         tf.summary.scalar('gaussian_GMI', metricsDict['gaussian_gmi_metric']),\n",
    "         tf.summary.scalar('sigmoid_GMI', metricsDict['sigmoid_gmi_metric'])]\n",
    "\n",
    "    epoche_summaries = tf.summary.merge(s) # without weight/bias histograms\n",
    "\n",
    "    summaries_dir = os.path.join(trainingParam.path,'tboard{}'.format(chParam.M),trainingParam.summaryString)\n",
    "    os.makedirs(summaries_dir, exist_ok=True)\n",
    "\n",
    "    train_writer = tf.summary.FileWriter(summaries_dir + '/train', sess.graph)\n",
    "else:\n",
    "    train_writer = None\n",
    "        \n",
    "sess.run(tf.global_variables_initializer())\n",
    "\n",
    "saver = tf.train.Saver()\n",
    "checkpoint_path = os.path.join(trainingParam.path,'checkpoint',trainingParam.filename,'best')\n",
    "if not os.path.exists(checkpoint_path):\n",
    "    os.makedirs(checkpoint_path)\n",
    "else:\n",
    "    pass\n",
    "#     print(\"Restoring checkpoint...\", flush=True)\n",
    "#     saver.restore(sess=sess,save_path=checkpoint_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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wWBQ8fHxionh73zgjHT26q9ovLjKuvdb+f5+96Xc113aktfdiNzX3X9s+aObNm2aS0hIcBdffLHLy8sLL5uXl+cuvvhil5CQ4KZOnepKSkrCZSUlJW3Wc845SS1evso/XOrSl77hvpT7uktf+ob7xrdmuNtuu81VVFS4//7v/w5fZe2ccydPnnQVFRVOktu7d687efJkeD1LlixxX//6111paan76KOP3NChQ92bb74ZPuaX3PeKG/6jl13/QGKLY/PQQw8555x75513XHp6uhswYICbOHFisyu5165d26Je06u0J06c2KJ869atETiCQO+h07jK2uqX91N2drbLz8+PdjPQBY29tZpQnfrFxShv7riz/tnIT209oMd/+7HqnBRr0oJx52vH2uV65513lJqaqhUrVuj222+XJJlZi/qN/2arqqq0cOFCvfTSSwoEAlqyZIl++MMfho/5wSdnK1T+ebO6n3zyiYYPH97j+wignpntcs5ld2pZAhk9rfHr2XEjUs/6MJYi80cKxxzww+kEMid70OOy0lK0aPKlBEODrLQU5c0dpx9el95j3xh05zFva+jNpqOBmZm2bdvWrN7WrVs1efJkJScnt9orP3z4sCZPnqyEhASNHj1a7777bpfbCvRmBDIQBb3pj5Rhw4Zp6dKlLYbelKQJEyZo48aNGjp0aIuyxMREzZkzRz//+c9bXe/MmTP1ta99TSUlJfq3f/s33XTTTTp+/Hi3tx/oLQhkAO3KycnR9OnTlZqa2mx+42hgEyZMaHU0sCuvvFJ33XWXRowY0aJs3759+tOf/qSHH35YgUBA3/nOd3TFFVf02vHIge5AIAOIuKKiIo0YMaLZ/danO9IY0NcQyAAijmE7gZYIZAARx7CdQEsEMoBWdWb4zTOVkZGhQ4cONesR95XhUIEzRSADaKHxXunHf/uxbl/9O+34+LNmQ282PhKycZhSqf42qGAwGB64pHG4zZqaGjnnFAwGVV1dLUkaNWqUvvrVr+rhhx9WMBjUK6+8ot27d+s73/lOdHYY8ACBDKCFnYdKVB2qU52TPv9gk64ePUwrVqzQxo0bFQgEtHz5cklSenq6AoGAPv30U11//fUKBAIqLi6WJH344YcKBAK64YYb9L//+78KBAK67rrrwtt44YUXlJ+fr5SUFOXm5uqll17S4MGDo7K/gA8YqQtA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\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# constellation before training\n",
    "[constellation,constellation_bits] = sess.run([enc_seed,xSeed])\n",
    "plt.figure(figsize=(8,8))\n",
    "plt.plot(constellation[:,0],constellation[:,1],'.')\n",
    "\n",
    "for ii in range(constellation.shape[0]):\n",
    "    bit_string = ''.join( [ str(int(x)) for x in allCombinations[ii,:].tolist()] )\n",
    "    plt.text(constellation[ii,0], constellation[ii,1], bit_string, fontsize=12)\n",
    "plt.axis('square');\n",
    "lim_ = 1.6\n",
    "plt.xlim(-lim_,lim_);\n",
    "plt.ylim(-lim_,lim_);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "bestLoss = 100000\n",
    "bestAcc = 0\n",
    "lastImprovement = 0\n",
    "epoche = 0\n",
    "nBatches = int(trainingParam.sampleSize/trainingParam.batchSize)\n",
    "batchSizeMultiples = 1\n",
    "batchSize = batchSizeMultiples * trainingParam.batchSize\n",
    "\n",
    "np_loss = []\n",
    "np_ber  = []\n",
    "np_gaussian_gmi  = []\n",
    "np_sigmoid_gmi  = []"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comment on the training procedure:\n",
    "The training gets stuck early when a large batch size is chosen. For this reason we start with a low batch size, and iterativley increase it after temporary convergence. Training with a low batch size introduces a more stochastic gradient estimation, which helps to get out of the local minima."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "START TRAINING ... \n",
      "epoche: 0025 - avgLoss: 0.24 - avgBer: 1.26e-01 - avgGaussianGmi: 2.90 - avgSigmoidGmi: 2.64\n",
      "epoche: 0050 - avgLoss: 0.19 - avgBer: 7.64e-02 - avgGaussianGmi: 3.12 - avgSigmoidGmi: 2.92\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0921 22:19:22.073544 139893023668032 deprecation.py:323] From /home/rasmus/.conda/envs/claudeOnline/lib/python3.6/site-packages/tensorflow/python/training/saver.py:1276: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use standard file APIs to check for files with this prefix.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "batchSize: 48, batchSizeMultiples: 3\n",
      "epoche: 0075 - avgLoss: 0.17 - avgBer: 7.24e-02 - avgGaussianGmi: 3.16 - avgSigmoidGmi: 3.00\n",
      "epoche: 0100 - avgLoss: 0.15 - avgBer: 6.42e-02 - avgGaussianGmi: 3.16 - avgSigmoidGmi: 3.11\n",
      "batchSize: 80, batchSizeMultiples: 5\n",
      "epoche: 0125 - avgLoss: 0.15 - avgBer: 6.26e-02 - avgGaussianGmi: 3.19 - avgSigmoidGmi: 3.12\n",
      "epoche: 0150 - avgLoss: 0.16 - avgBer: 6.65e-02 - avgGaussianGmi: 3.15 - avgSigmoidGmi: 3.09\n",
      "batchSize: 112, batchSizeMultiples: 7\n",
      "epoche: 0175 - avgLoss: 0.16 - avgBer: 6.42e-02 - avgGaussianGmi: 3.15 - avgSigmoidGmi: 3.10\n",
      "batchSize: 144, batchSizeMultiples: 9\n",
      "epoche: 0200 - avgLoss: 0.15 - avgBer: 5.98e-02 - avgGaussianGmi: 3.17 - avgSigmoidGmi: 3.15\n",
      "epoche: 0225 - avgLoss: 0.16 - avgBer: 6.23e-02 - avgGaussianGmi: 3.16 - avgSigmoidGmi: 3.11\n",
      "batchSize: 176, batchSizeMultiples: 11\n",
      "epoche: 0250 - avgLoss: 0.15 - avgBer: 6.20e-02 - avgGaussianGmi: 3.15 - avgSigmoidGmi: 3.13\n",
      "epoche: 0275 - avgLoss: 0.15 - avgBer: 6.23e-02 - avgGaussianGmi: 3.17 - avgSigmoidGmi: 3.13\n",
      "batchSize: 208, batchSizeMultiples: 13\n",
      "epoche: 0300 - avgLoss: 0.15 - avgBer: 5.99e-02 - avgGaussianGmi: 3.16 - avgSigmoidGmi: 3.15\n",
      "batchSize: 240, batchSizeMultiples: 15\n",
      "epoche: 0325 - avgLoss: 0.14 - avgBer: 5.85e-02 - avgGaussianGmi: 3.18 - avgSigmoidGmi: 3.16\n",
      "epoche: 0350 - avgLoss: 0.15 - avgBer: 6.45e-02 - avgGaussianGmi: 3.13 - avgSigmoidGmi: 3.12\n",
      "epoche: 0375 - avgLoss: 0.15 - avgBer: 6.09e-02 - avgGaussianGmi: 3.19 - avgSigmoidGmi: 3.15\n",
      "epoche: 0400 - avgLoss: 0.15 - avgBer: 6.10e-02 - avgGaussianGmi: 3.15 - avgSigmoidGmi: 3.13\n"
     ]
    }
   ],
   "source": [
    "print( 'START TRAINING ... ', flush=True )\n",
    "while(True):\n",
    "    epoche = epoche + 1\n",
    "\n",
    "    sess.run(resetOps)\n",
    "    \n",
    "    # train AE with iteratively increasing batch size\n",
    "    for batch in range(0,nBatches):\n",
    "        feedDict = {X: cu.generateBitVectors(batchSize,chParam.M)}\n",
    "        sess.run(d_sigmoid_loss, feed_dict=feedDict)\n",
    "    \n",
    "    # gather performance metrics with large batch size\n",
    "    for batch in range(0,nBatches):\n",
    "        feedDict = {X: cu.generateBitVectors(trainingParam.sampleSize,chParam.M)}\n",
    "        sess.run(updateOps, feed_dict=feedDict)\n",
    "\n",
    "    [outAvgLoss, outAvgBer, outAvgGaussianGmi, outAvgSigmoidGmi] = sess.run(list(meanMetricOpsDict.values()), feed_dict=feedDict)\n",
    "\n",
    "    np_loss.append( outAvgLoss )\n",
    "    np_ber.append( outAvgBer )\n",
    "    np_gaussian_gmi.append( outAvgGaussianGmi )\n",
    "    np_sigmoid_gmi.append( outAvgSigmoidGmi )\n",
    "    \n",
    "    if trainingParam.summaries:\n",
    "        epocheSummaries = sess.run(epoche_summaries, feed_dict=feedDict)\n",
    "        train_writer.add_summary(epocheSummaries,epoche)\n",
    "\n",
    "    if outAvgLoss < bestLoss:\n",
    "        bestLoss = outAvgLoss\n",
    "        lastImprovement = epoche\n",
    "        saver.save(sess=sess,save_path=checkpoint_path)\n",
    "\n",
    "    # convergence check and increase empirical evidence\n",
    "    if epoche - lastImprovement > trainingParam.earlyStopping:\n",
    "\n",
    "        saver.restore(sess=sess,save_path=checkpoint_path)\n",
    "        bestLoss = 10000\n",
    "        lastImprovement = epoche\n",
    "\n",
    "        # increase empirical evidence\n",
    "        batchSizeMultiples = batchSizeMultiples + 2\n",
    "        batchSize = batchSizeMultiples * trainingParam.batchSize\n",
    "        if batchSizeMultiples >= 17:\n",
    "            break;\n",
    "\n",
    "        print(\"batchSize: {}, batchSizeMultiples: {}\".format(batchSize,batchSizeMultiples))\n",
    "\n",
    "    if epoche%trainingParam.displayStep == 0:\n",
    "        print('epoche: {:04d} - avgLoss: {:.2f} - avgBer: {:.2e} - avgGaussianGmi: {:.2f} - avgSigmoidGmi: {:.2f}'.format(epoche,outAvgLoss,outAvgBer,outAvgGaussianGmi,outAvgSigmoidGmi),flush=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f3b08656f98>]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "saver.restore(sess=sess,save_path=checkpoint_path)\n",
    "np_loss = np.array( np_loss )\n",
    "np_ber  = np.array( np_ber )\n",
    "np_gaussian_gmi  = np.array( np_gaussian_gmi )\n",
    "np_sigmoid_gmi  = np.array( np_sigmoid_gmi )\n",
    "plt.plot( np_loss )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f3b104c2c50>]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot( np_gaussian_gmi )\n",
    "plt.plot( np_sigmoid_gmi )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# constellation after training\n",
    "[constellation,constellation_bits] = sess.run([enc_seed,xSeed])\n",
    "plt.figure(figsize=(8,8))\n",
    "plt.plot(constellation[:,0],constellation[:,1],'x')\n",
    "\n",
    "for ii in range(constellation.shape[0]):\n",
    "    bit_string = ''.join( [ str(int(x)) for x in allCombinations[ii,:].tolist()] )\n",
    "    plt.text(constellation[ii,0]+0.01, constellation[ii,1]+0.01, bit_string, fontsize=12)\n",
    "plt.axis('square');\n",
    "lim_ = 1.6\n",
    "plt.xlim(-lim_,lim_);\n",
    "plt.ylim(-lim_,lim_);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "finalMetrics: {'GaussianGMI': 3.1765318, 'SigmoidGMI': 3.1487226, 'BER': 0.060694996, 'xentropy': 0.14751528}\n"
     ]
    }
   ],
   "source": [
    "sess.run(resetOps)\n",
    "for batch in range(0,100):\n",
    "    feedDict = {X: cu.generateBitVectors(1000,chParam.M)}\n",
    "    sess.run(updateOps, feed_dict=feedDict)\n",
    "[outAvgLoss, outAvgBer, outAvgGaussianGmi, outAvgSigmoidGmi] = sess.run(list(meanMetricOpsDict.values()), feed_dict=feedDict)\n",
    "finalMetrics = { 'GaussianGMI': outAvgGaussianGmi, 'SigmoidGMI': outAvgSigmoidGmi, 'BER': outAvgBer, 'xentropy': outAvgLoss }\n",
    "\n",
    "print( 'finalMetrics:', finalMetrics )"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
